﻿/**
*   name        :   $.InteractiveApi
*   description :   提供客户端访问服务器的通用底层方法实现
*   version     :   1.0.0.0
*   author      :   苟向阳
*   created on  :   2017-5-31 17:39:22
*   modified on :   2017-5-31 17:39:22
*   usage       :   $.api.ajax(o) o is jquery ajax parameters list, or a object parameter;
*                   like $.api.post('url', {data: 'data'}, successCallBack);
*                   or $.api.post({url: 'url', data: {}, sucess: successCallBack }); 
*/

if (typeof jQuery === 'undefined') {
    throw new Error('api JavaScript requires jQuery');
}

/**
* GlobalMask structure:
* {
*   getMaskTemplate     :   定义 GlobalMask 模板
*   loadGlobalMask      :   装载 GlobalMask
*   unloadGlobalMask    :   卸载 GlobalMask
* }
*/
var GlobalMask = new function () {
    "use strict";
    var that = this;

    // global mask template setting
    this.getMaskTemplate = function () {
        var mask =
            '<div id="__globalMask" class="modal-backdrop fade in" data-level="0" style="z-index:99999; display:none;">' +
            '<div style="z-index:100000; width:56px; height:20px; margin-top:18%; margin-left:auto; margin-right:auto;"><img src="/KendoUI/styles/Bootstrap/loading-image.gif"/></div>' +
            '</div>';
        return mask;
    };

    // load to show global mask
    this.loadGlobalMask = function () {
        var globalMask = $('#__globalMask');
        //if ($.com.isNullOrEmpty(globalMask)) {
        //    $(document.body).append(that.getMaskTemplate());
        //    globalMask = $('#__globalMask');
        //}

        var level = globalMask.attr("data-level");
        if (!$.com.hasValue(level) || !$.isNumeric(level) || level == 0) {
            level = 0;
            globalMask.fadeIn(50).show();
        }
        level = Number(level) + 1;
        globalMask.attr("data-level", level);
    };

    // unload to hide global mask
    this.unloadGlobalMask = function () {
        var globalMask = $('#__globalMask');
        if (!$.com.isNullOrEmpty(globalMask)) {
            var level = globalMask.attr("data-level");
            if (!$.com.hasValue(level) || !$.isNumeric(level)) {
                level = 0;
            }
            level = Number(level) - 1;
            if (level <= 0) {
                level = 0;
                globalMask.fadeOut().hide();
            }

            globalMask.attr("data-level", level);
        }
    };
};

/**
* $.InteractiveApi structure:
* {
*   ajax    :   default jquery ajax request method, default type is post
*   get     :   http get jquery ajax request
*   insert  :   a alias of http get jquery ajax request
*   post    :   http post jquery ajax request 
*   update  :   a alias of http put jquery ajax request
*   put     :   http put jquery ajax request
*   delete  :   http delete jquery ajax request
* }
*/
$.api = new function () {
    'use strict';

    // default
    var defaults = {
        cache: false,
        async: true,
        prompt: false,
        url: undefined,
        type: 'POST',
        //dataType: 'json',
        //contentType: 'application/json',
        //contentType: 'application/x-www-form-urlencoded',
        data: undefined,
        beforeSend: undefined,
        success: undefined,
        successText: '已完成!',
        error: undefined,
        errorText: '服务器错误, 请联系管理员处理!',
        complete: undefined,
        value: undefined
    };

    //merge options data
    var extend = function () {
        var options = {};
        if (arguments.length !== 0 && !$.com.isNullOrEmpty(arguments[0])) {
            if (arguments[0].length === 1 && typeof arguments[0][0] === 'object') {
                options = arguments[0][0];
            } else {
                $.each(arguments[0], function (i, x) {
                    if ($.com.hasValue(x)) {
                        switch (typeof x) {
                            case 'boolean':
                                options.async = x;
                                break;
                            case 'object':
                                options.data = x;
                                break;
                            case 'string':
                                // 字符串参数取值顺序: url->data->type
                                if ($.com.hasValue(options.url)) {
                                    if ($.com.hasValue(options.data)) {
                                        options.type = x;
                                    } else {
                                        options.data = x;
                                    }
                                } else {
                                    options.url = x;
                                }
                                break;
                            case 'function':
                                // 方法参数取值顺序: success->error->beforeSend->complete
                                if ($.com.hasValue(options.success)) {
                                    if ($.com.hasValue(options.error)) {
                                        if ($.com.hasValue(options.beforeSend)) {
                                            options.complete = x;
                                        } else {
                                            options.beforeSend = x;
                                        }
                                    } else {
                                        options.error = x;
                                    }
                                } else {
                                    options.success = x;
                                }
                                break;
                            default:
                                break;
                        }
                    }
                });
            }
        }

        return options;
    };

    //send jquery ajax request
    var ajaxSetup = function (options) {
        options = $.extend(true, {}, defaults, options);

        var success = function (data, result, xhr) {
            options.value = data;
            if (xhr.status === 200) {
                options.data = $.com.dataAdapter(data);
                options.value = options.data;
                let then = function () {
                    $.com.onSuccess(options, options.value, xhr);
                };

                if (options.prompt) {
                    app.success(options.successText).then(() => then());
                } else {
                    then();
                }
            }
        };
        var error = function (xhr) {
            let then = function () {
                $.com.onError(options, xhr);
            };

            //暂时以这种方式替代原逻辑, 服务器发生错误时始终弹出提示
            if (options.action !== 'onImport' || options.prompt) {
                if (xhr.status >= 400 && xhr.status < 500) {
                    options.errorText = (xhr.status === 401) ? '您还没有登录, 请先登录!' : xhr.responseText;
                }

                app.error(options.errorText).then(() => then());
            } else {
                then();
            }
        };

        var settings = {
            beforeSend: function (xhr) {
                //xhr.setRequestHeader(ClientConst.NonRepeatableTimeStamp, $('#' + ClientConst.NonRepeatableTimeStamp).val());
                var result = $.com.beforeSend(options, xhr);

                if (options.async && result !== false) {
                    GlobalMask.loadGlobalMask();
                }

                return result;
            },
            success: function (data, result, xhr) {
                options.value = data;
                if (xhr.status === 200) {
                    success(data, result, xhr);
                } else {
                    error(xhr);
                }
            },
            error: function (xhr) {
                //chrome 浏览器在 post 提交的数据带附件的时候, 会出现服务器端返回 OK 但是客户端进了 error 的情况, 这时候, 一样按照 success处理, 但是这种情况下拿不到服务器返回的 data 数据
                if (xhr.status === 200) {
                    success(null, null, xhr);
                } else {
                    error(xhr);
                }
            },
            complete: function (xhr) {
                $.com.onComplete(options, xhr);

                if (options.async) {
                    GlobalMask.unloadGlobalMask();
                }

                //var timestamp = xhr.getResponseHeader(ClientConst.NonRepeatableTimeStamp);
                //if ($.com.hasValue(timestamp)) {
                //    $('#' + ClientConst.NonRepeatableTimeStamp).val(timestamp);
                //}
            }
        };

        //process options;
        var result = $.extend(true, {}, options, settings);
        result.url = $.com.encodeURI(result.url);
        if ($.com.hasValue(result.data)) {
            result.contentType = 'application/json';
            result.data = JSON.stringify(result.data);
        }

        return result;
    };

    //ajax call api ajax method
    this.ajax = function () {
        var settings = extend(arguments);
        settings = ajaxSetup(settings);
        $.ajax(settings);
        return settings.value;
    };

    //ajax call api get method
    this.get = function () {
        var settings = extend(arguments);
        settings.type = 'GET';
        settings = ajaxSetup(settings);
        $.get(settings);
        return settings.value;
    };

    //ajax call api post method
    this.post = function () {
        var settings = extend(arguments);
        settings.type = 'POST';
        settings = ajaxSetup(settings);
        $.post(settings);
        return settings.value;
    };

    //ajax call api put method
    this.put = function () {
        var settings = extend(arguments);
        settings.type = 'PUT';
        settings = ajaxSetup(settings);
        $.ajax(settings);
        return settings.value;
    };

    //ajax call api delete method
    this.delete = function () {
        var settings = extend(arguments);
        settings.type = 'DELETE';
        settings = ajaxSetup(settings);
        $.ajax(settings);
        return settings.value;
    };
};

var fetchClient = new function () {
    'use strict';
    var that = this;

    this.loading = function () {
        GlobalMask.loadGlobalMask();
    };

    this.loaded = function () {
        setTimeout(GlobalMask.unloadGlobalMask, 300);
    };

    this.fetch = function (url, options) {
        if ($.com.isIE()) {
            url = encodeURI(url);
        }

        options = options || {};
        var method = "GET";
        if ($.com.hasValue(options.body)) {
            method = "POST";
            options.body = JSON.stringify(options.body);
        }

        var op = $.extend({
            headers: {
                "Accept": "application/json;odata=verbose",
                "Content-Type": "application/json;odata=verbose;charset=utf-8"
            },
            method: method,
            mode: "no-cors",
            cache: "no-cache",
            credentials: "include"
        }, options);

        return Promise.resolve()
            .then(function (x) {
                that.loading();
            })
            .then(function (x) {
                return fetch(url, op);
            })
            .then(function (x) {
                that.loaded();
                if (x.ok) {
                    return x.json().then(function (x) {
                        return $.com.dataAdapter(x);
                    });
                }
            }).catch(function (e) {
                that.loaded();
                throw e;
            });
    };
};

$.fetch = function (url, options) {
    return fetchClient.fetch(url, options);
};

